/*
    Copyright (C) 2011 Rodrigo Castaño - Hugo Arregui, FuDePAN

    This file is part of the Prot-Filer Library

    Prot-Filer is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Prot-Filer is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Prot-Filer.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef FILER_BASE_H

#define FILER_BASE_H

#include <vector>
#include <string>
#include <mili/mili.h>

#include "prot-filer/definitions.h"
#include "prot-filer/angles.h"


#define DIM 3

namespace prot_filer
{

struct AnglesMapping;
struct AnglesData;
typedef std::vector<ATOM> BasicProtein;
typedef unsigned int FragmentId;
typedef std::vector<FragmentId> FragmentIds;

class FormatMixin
{
public:
    FormatMixin() :
        _isOpen(false)
    {};
    virtual ~FormatMixin()
    {
        //TODO: check this
        //if (_isOpen)
        //_close();
    };
    bool open(const std::string& name)
    {
        _isOpen = true;
        return _open(name);
    }
    void close()
    {
        _close();
        _isOpen = false;
    }
    bool isOpen() const
    {
        return _isOpen;
    }
    void checkOpen() const
    {
        if (!_isOpen)
            throw std::runtime_error("Attempted access without calling open() first.");
    }
private:
    virtual void _close() = 0;
    virtual bool _open(const std::string&) = 0;
    bool _isOpen;
};

struct FormatWriter : public FormatMixin
{
    virtual ~FormatWriter() {};
};

using biopp::Coord3d;
typedef biopp::Structure<Coord3d> Protein;

struct Coord3DReader
{
    virtual bool open(const std::string& name) = 0;
    virtual bool read(BasicProtein&) = 0;
    virtual bool read(Protein&) = 0;
    virtual size_t get_atom_number() const = 0;
    virtual void close() = 0;
    virtual ~Coord3DReader() {};
};

struct Coord3DSeqReader : public virtual Coord3DReader
{
    virtual bool read(BasicProtein&, size_t n) = 0;
    virtual bool read(Protein&, size_t n) = 0;
    virtual ~Coord3DSeqReader() {};
};

struct SimpleAnglesReader
{
    virtual AnglesMapping* get_angles_mapping() const = 0;
    virtual size_t get_atom_number() const = 0;
    virtual bool read(AnglesData&) = 0;
    virtual void close() = 0;
    virtual ~SimpleAnglesReader() {};
};

struct AnglesReader : public SimpleAnglesReader
{
    virtual AnglesMapping* get_angles_mapping() const = 0;
    virtual size_t get_atom_number() const = 0;
    virtual bool open(const std::string& name) = 0;
    virtual bool read(AnglesData&) = 0;
    virtual bool read(AnglesData&, size_t n) = 0;
    virtual void close() = 0;
    virtual ~AnglesReader() {};
};

class Fragments
{
public:
    virtual unsigned int get_fragment_size() const = 0;
    virtual AnglesData& operator[](unsigned int i) = 0;
    virtual ~Fragments() {};
};

struct FragmentsAnglesReader : public SimpleAnglesReader
{
    virtual AnglesMapping* get_angles_mapping() const = 0;
    virtual size_t get_atom_number() const = 0;
    virtual bool open(Fragments* _fragments, const std::string& name) = 0;
    virtual bool read(AnglesData&) = 0;
    virtual void close() = 0;
    virtual ~FragmentsAnglesReader() {};
};
}
#endif
